iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0

常用指令

Set 是一堆不重複的字串,沒有順序。

  • SADD key member ...(加進去,回傳真的加進去幾個,重複的算 0)
    https://ithelp.ithome.com.tw/upload/images/20260919/20184209ojZX8QUnC9.png

  • SMEMBERS key(全部撈出來)
    https://ithelp.ithome.com.tw/upload/images/20260919/20184209DG0Gveet4a.png

  • SISMEMBER key member(1 表示存在,0 表示不存在)
    https://ithelp.ithome.com.tw/upload/images/20260919/20184209wE8YpBAL13.png

  • SCARD key(有幾個)
    https://ithelp.ithome.com.tw/upload/images/20260919/20184209HRV9LAzsQ2.png

  • SREM key member ...(刪掉,回傳刪掉幾個)
    https://ithelp.ithome.com.tw/upload/images/20260919/20184209z75cReQzoK.png

  • SINTER key ...(交集,每個集合裡都有的)
    https://ithelp.ithome.com.tw/upload/images/20260919/20184209VmJOSixUfI.png

  • SUNION key ...(聯集,合起來自動去重)
    https://ithelp.ithome.com.tw/upload/images/20260919/20184209OygkYQyJfE.png

  • SDIFF key ...(差集,在第一個裡面但不在後面那些裡面的)
    https://ithelp.ithome.com.tw/upload/images/20260919/20184209ljljUx4ZGP.png

  • SPOP key count(隨機抽走 count 個,抽走就從集合裡消失)
    https://ithelp.ithome.com.tw/upload/images/20260919/20184209VgCW7r0wFl.png

商品標籤

一個商品有很多標籤,一個標籤底下也有很多商品。存的時候反過來,用「標籤 → 商品集合」:

SADD tag:3C p1 p2 p3
SADD tag:sale p2 p3 p4

要找「同時是 3C 又特價」的商品,SQL 需要多開一張關聯表再 JOIN,這裡一個指令就好:

SINTER tag:3C tag:sale   # p2 p3

多一個條件就多一個 key,指令本身不用改。另外兩個也很好用:

  • SUNION tag:3C tag:sale(3C 或特價,可以當推薦池)
  • SDIFF seen:1 bought:1(看過但沒買的)

Java 是用 SetOperations:

private final SetOperations<String, String> set;

public TagController(StringRedisTemplate redis) {
    this.set = redis.opsForSet();
}

/** 打標籤:同一件商品重複打同一個標籤,集合裡還是只有一筆 */
@PostMapping("/{productId}")
public Map<String, Object> tag(@PathVariable String productId, @RequestParam List<String> tags) {
    tags.forEach(tag -> set.add("tag:" + tag, productId));
    return Map.of("productId", productId, "tags", tags);
}

/** 同時有這些標籤的商品,一個 SINTER 做完 */
@GetMapping("/search")
public Set<String> search(@RequestParam List<String> tags) {
    return set.intersect(tags.stream().map(t -> "tag:" + t).toList());
}

先打四件商品的標籤,再篩「3C + 特價」:

curl -X POST "http://localhost:8080/tag/p1?tags=3C"
curl -X POST "http://localhost:8080/tag/p2?tags=3C,sale"
curl -X POST "http://localhost:8080/tag/p3?tags=3C,sale"
curl -X POST "http://localhost:8080/tag/p4?tags=sale"

curl "http://localhost:8080/tag/search?tags=3C,sale"

https://ithelp.ithome.com.tw/upload/images/20260919/20184209zZgqm6voHU.png

抽獎

報名用 SADD,同一個人連按十次也只會有一筆。開獎用 SPOP:

SPOP lottery:1 3

一次抽 3 個,抽出來的會直接從集合裡移除,所以不可能抽到同一個人兩次,也不用另外記誰中過獎。

/** 抽獎:一次抽 count 個,抽出來的就從池子裡移除 */
@PostMapping("/draw")
public Map<String, Object> draw(@RequestParam long count) {
    List<String> winners = set.pop("lottery:1", count);
    return Map.of("winners", winners, "left", set.size("lottery:1"));
}

五個人報名:

curl -X POST "http://localhost:8080/lottery/join?user=u1"   # u1 ~ u5 各打一次

https://ithelp.ithome.com.tw/upload/images/20260919/20184209wbUarEQNNn.png
再抽三個:

curl -X POST "http://localhost:8080/lottery/draw?count=3"

https://ithelp.ithome.com.tw/upload/images/20260919/20184209JZkIUqvZ2c.png

SINTER 的代價

SINTER 看起來很好用,但資料量一大,背後的成本高。

假設有兩個各 50 萬件商品的標籤,Redis 算交集的方式很直覺:從其中一邊拿出第 1 個商品,去另一邊問「你有沒有這個」,再拿第 2 個去問,整整問完 50 萬次(Redis 會挑元素比較少的那一邊來走,所以看的是小的那個集合有多大)。

這會造成兩個問題:

  • 一個人慢,全部的人排隊:Day 3 說過 Redis 是單執行緒,一次只處理一個指令。這 50 萬次比對就算只花 65 毫秒(0.065 秒),這段時間整台 Redis 是停住的,其他人查快取、登入、看購物車全部在外面等
  • 只是要顯示「找到幾件」,卻把整包資料撈回來:Redis 7.0 之後有 SINTERCARD,專門只回傳數量,不用把幾十萬筆傳出去

但光換成 SINTERCARD 沒有用,那 50 萬次比對還是得跑完,省下的只有傳回網路的時間。要加上 LIMIT 100,Redis 數到 100 筆就停手不再往下看,耗時才會從幾萬微秒掉到幾十微秒。

而且很多場景本來就不需要精確的數字:

  • 前端顯示「100+」:畫面上不用寫「符合條件的有 23,847 件」,給個「超過 100 件」就夠了,LIMIT 100 回傳 100 就印 100+
  • 翻頁前先確認有沒有下一頁:一頁顯示 20 筆,用 LIMIT 21 問一次就知道後面還有沒有,不用把幾萬筆的交集整包算完

大集合取交集會卡住整台 Redis,只是要算數量的話一定要加 LIMIT。

相關範例程式碼可以參考 https://github.com/gary880306/redis-30days/tree/dev

第一週小結

型別 重點 用途
String 一個 key 對一個值 商品快取、INCR 計數器
Hash key 底下再掛一層 field 購物車,HINCRBY 只改一項
List 有順序,兩頭都能進出 最近瀏覽、當 Queue
Set 不重複、沒順序、能做集合運算 商品標籤、抽獎

選用的時候大致是這樣分:只改其中一個欄位就用 Hash,要照順序就用 List,不能重複或要取交集就用 Set。

明天

排行榜要照銷量排,List 的順序是「誰先被推進去」,Set 根本沒有順序,兩個都對不上。繼續來看會自己照分數排序的 Sorted Set/images/emoticon/emoticon31.gif


上一篇
Day 6|List
下一篇
Day 8|Sorted Set 排行榜
系列文
從購物車到秒殺:30 天 Redis 高併發自學筆記 共 21 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言